package scm

import (
	"bytes"
	"log"
	"os/exec"
	"time"
)

// Connector represents an object responsible for connecting to a certain SCM
// repository and performing local updates. 
type Connector interface {
	init() *exec.Cmd
	update() (error, bool)
	workingDir() string
}

// connector : minimal datastructure for Connector implementation
type connector struct {
	url string
	dir string
}

const (
	GIT = iota // git SCM system
	SVN        // subversion SCM system
)

// Connect creates a Connector for the repository located at url.
// The returned Connector will fetch files under the directory
// with path dir. The sys parameter specifies the SCM system to use. 
func Connect(url string, dir string, sys int) Connector {
	switch sys {
	case GIT:
		return &gitConnector{url, dir}
	case SVN:
		return &svnConnector{url, dir}
	default:
		log.Printf("Unknown SCM system : %d", sys)
	}
	return nil
}

// Init performs the first repository checkout for the provided 
// Connector. The repository content is copied under the Connector's working 
// directory.
func Init(conn Connector) error {
	cmd := conn.init()
	buf := bytes.NewBuffer(make([]byte, 0))
	cmd.Stderr = buf
	err := cmd.Run()
	if err != nil {
		log.Println(err.Error())
		log.Printf("stderr content : %s\n", buf)
	}
	return err
}

// Poll starts polling the conn SCM Connector every intervalNs nanoseconds.
// When a change is detected, it calls the provided callback, passing the 
// Connector working directory as argument.
func Poll(conn Connector, callback func(string), intervalNs int64) {
	ticker := time.Tick(10 * time.Minute)
	for {
		select {
		case <-ticker:
			if err, updated := conn.update(); err == nil && updated {
				callback(conn.workingDir())
			} else if err != nil {
				log.Printf("[ERROR] Unable to update %v : %s", conn, err)
			}
		}
	}
}
